package pers.cz.sharindmerge;

import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.session.SqlSession;
import pers.cz.model.Entity;
import pers.cz.model.SystemPartitionConstParam;
import pers.cz.model.TestPartition;
import pers.cz.spring.SpringContextUtil;
import pers.cz.thread.Master;
import pers.cz.thread.QueryWorker;
import pers.cz.utils.PartitionUtil;

import java.util.*;

/**
 * 分表查询结果合并
 * @program: PostGirl-panent
 * @description: ShardingTableMerge
 * @author: Cheng Zhi
 * @create: 2022-05-03 20:53
 **/
public class ShardingTableMerge {

    private static final String param_name = "mod_count";

    /**
     * 思路：查询启动多少个线程、根据分表数量来决定
     */

    /**
     * 获取分表总数
     * @param tableName
     * @return
     */
    private Integer getTableModCount(String tableName) {

        Map<String, SystemPartitionConstParam> constsContext = SpringContextUtil.getBean(PartitionUtil.class).getConstsContext();
        String key = tableName + "|" + param_name;
        SystemPartitionConstParam systemPartitionConstParam = constsContext.get(key);

        return Integer.valueOf(systemPartitionConstParam.getParamValue());
    }

    /**
     * 批量查询合并结果后返回，不做分页
     * @param tableName
     * @param clazz
     */
    public void batchQuery(String tableName, Class clazz) {

        this.batchQuery(tableName, clazz, null, null);
    }

    /**
     * 批量查询合并结果返回，内存中分页
     * @param tableName
     * @param clazz
     */
    public void batchQuery(String tableName, Class clazz, Integer start, Integer limit) {
        // 创建一个有序集合LinkedList,边放边排序
        List<Entity> linkedList = new LinkedList<Entity>();
        List<Entity> resultLinkedList = new LinkedList<Entity>();
        Integer end = 0;
        boolean isPage = true;
        if (start == null || limit == null) {
            isPage = false;
            end = start + limit; // end是最后一个元素
        }

        Integer tableModCount = getTableModCount(tableName);
        Master master = new Master(new QueryWorker(), tableModCount);
        for (int i= 0; i<tableModCount; i++) {
            master.submit(clazz, i);
        }
        master.execute();
        int re = 0;
        Map<String,Object> resultMap=master.getResultMap();
        //不需要等待所有的Worker都执行完即可进行合并操作 || !master.isComplete()
        while(resultMap.size()>0 || !master.isComplete()) {
            Set<String> keys=resultMap.keySet(); //开始计算最终结果
            String key=null;

            for (String k:keys) {
                key=k;
                break;
            }

            if(key!=null) {
                Map<SqlSession, Cursor> o = (Map<SqlSession, Cursor>) resultMap.get(key);
                for (Map.Entry<SqlSession, Cursor> entry : o.entrySet()) {
                    Cursor cursor= entry.getValue();
                    SqlSession session = entry.getKey();
                    try {
                        Iterator<Object> iterator = cursor.iterator();
                        while (iterator.hasNext()) {
                            TestPartition next = (TestPartition) iterator.next();
                            orderedList(next, (LinkedList<Entity>) linkedList);

                            if (isPage) {
                                // 分页怎么搞全局数据，查询的时候就来个order by

                            }
                        }
                        session.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            if(key!=null)
                resultMap.remove(key); // 移除已经被计算
        }

        for (Entity entity : linkedList) {
            System.out.println(entity.getSoNbr());
        }
        System.out.println(re);
    }

    /**
     * 排序
     * @param entity
     * @param linkedList
     */
    private void orderedList(Entity entity, LinkedList<Entity> linkedList) {

        if (entity == null) {
            return;
        }

        // 判断主键是否为空
        if (entity.getSoNbr() == null) {
            return;
        }

        if(linkedList.size() == 0) {
            linkedList.add(entity);
        } else {
            if(entity.getSoNbr() < linkedList.getFirst().getSoNbr()) {
                linkedList.addFirst(entity);
            }else {
                boolean insertFlag = false;
                for (Entity e : linkedList) {
                    if (entity.getSoNbr() < e.getSoNbr()) {
                        int index = linkedList.indexOf(e);
                        linkedList.add(index, entity);
                        insertFlag = true;
                        break;
                    }
                }
                if (!insertFlag) {
                    linkedList.addLast(entity);
                }
            }
        }
    }
}
